<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋</title>
    <style>
        canvas {
            display: block;
            margin: 50px auto;
            box-shadow: -2px -2px 2px #000, 5px 5px 5px #000;
        }
    </style>
</head>

<body>
    <div style="margin-left:  600px; margin-top: 200px;">

        <button onClick="_create('user')">打开个人信息库</button>
        <button onClick="_delete('user')">删除个人信息库</button><br /><br />
        姓名：<input type="text" id="name"><br />
        年龄：<input type="number" id="age" min=1><br />
        账号：<input type="number" id="sc" min=1><br />
        ID : &nbsp;<input type="text" id="add"><br />
        性别：<br />
        男：<input type="radio" id="nan" name="xb" value="male" checked>
        女：<input type="radio" id="nv" name="xb" value="female"><br />

        <button onClick="_add()">添加数据</button>
        <button onClick="_get()">获取数据</button><br />
        <p id="display"></p>
        成功获取数据后可开始游戏
        <p style="color: blueviolet; font-size: 24px; font-weight: 400;margin-left: 85px;margin-top: 50px;">五子棋对决</p>
    </div>
    <canvas id="chess" width="450px" height="450px"></canvas>

    <script type="text/javascript">
        var db;
        var request;  //请求标识
        var objectStore;
        //创建数据库并判断是否成功打开数据库，成功弹出成功窗口失败弹出失败窗口
        function _create(dbName) {
            request = indexedDB.open(dbName, 1);

            request.onerror = function () {
                alert("打开个人信息库失败:" + event.target.message);
            }
            request.onsuccess = function (event) {
                alert("打开个人信息库成功!");
                db = event.target.result;
                var transaction = db.transaction(["info"], "readwrite");
                //得到的是一个IDBOpenDBRequest对象

                objectStore = transaction.objectStore("info");
            }
            request.onupgradeneeded = function (event) {
                alert("版本变化！");
                db = event.target.result;
                objectStore = db.createObjectStore("info", { keyPath: "userId", autoIncrement: true });
            }
        }
        //删除数据库函数，用警告框提示是否成功，需在浏览器控制台查看
        function _delete(dbName) {
            try {
                request = indexedDB.deleteDatabase(dbName);
                request.onerror = function () {
                    alert("删除个人信息库失败:" + event.target.message);
                }
                request.onsuccess = function (event) {
                    alert("删除个人信息库成功!");
                }
            } catch (e) {
                alert(e.getMessage);
            }
        }
        //利用游标搜索数据的方法通过事务可以根据已知的键检索单个对象，先在事务
        // 内部创建游标。游标是指向结果集的指针。游标指针会先指向结果中的第一项，在接到
        // 查找下一项的指令时，指向下一项。
        function _get(argument) {
            var p = document.getElementById("display");
            p.innerHTML = "";//获取数据前先清理一下页面已显示的数据
            if (!db) {
                alert("请打开个人信息库先！");
                return false;
            }
            var store = db.transaction("info").objectStore("info");
            var keyRange = IDBKeyRange.lowerBound(0);      //规定keyRange从0开始
            var cursorRequest = store.openCursor(keyRange);  //按照keyRange的设置开启游标

            cursorRequest.onsuccess = function (e) {

                var result = e.target.result;

                if (!!result == false)
                    return;

                _render(result.value);
                result.continue();     //这边执行轮询读取
            };

            cursorRequest.onerror = function (e) {
                alert("数据检索失败！");
            };

        }

        function _render(e) {
            var p = document.getElementById("display");
            p.innerHTML += "姓名:" + e.name + " 年龄:" + e.age + " 账号:" + e.sc + " ID:" + e.add + " 性别:" + e.xb + "<br />";
        }
        //添加数据条功能函数，先打开数据库，后利用索引添加一条数据到数据库中
        function _add(argument) {
            var name = document.getElementById("name").value;
            var age = document.getElementById("age").value;
            var sc = document.getElementById("sc").value;
            var add = document.getElementById("add").value;
            var xb, flag = document.getElementById("nan").checked;
            if (flag)
                xb = "男";
            else
                xb = "女";
            var detail = {
                name: name,
                age: age,
                sc: sc,
                add: add,
                xb: xb
            }
            if (!db) {
                alert("请打开个人信息库先！");
                return false;
            }
            var transaction = db.transaction(["info"], "readwrite");
            objectStore = transaction.objectStore("info");
            objectStore.add(detail);
            alert("添加成功！");
        }
    </script>

    <script>


        var chess = document.getElementById('chess')  //根据指定的 id 属性值得到对象。返回 id 属性值
        var context = chess.getContext('2d')
        var me = true
        var chessBoard = []
        var over = false


        // 赢法数组
        var wins = []

        // 赢法的统计数组
        var myWin = []
        var computerWin = []

        for (var i = 0; i < 15; i++) {
            chessBoard[i] = []
            for (var j = 0; j < 15; j++) {
                chessBoard[i][j] = 0
            }
        }

        // 三维数组
        for (var i = 0; i < 15; i++) {
            wins[i] = []
            for (var j = 0; j < 15; j++) {
                wins[i][j] = []
            }
        }

        // 横线赢法
        var count = 0
        for (var i = 0; i < 15; i++) {
            for (var j = 0; j < 11; j++) {
                // wins[0][0][0] = true
                // wins[0][1][0] = true
                // wins[0][2][0] = true
                // wins[0][3][0] = true
                // wins[0][4][0] = true

                // wins[0][1][1] = true
                // wins[0][2][1] = true
                // wins[0][3][1] = true
                // wins[0][4][1] = true
                // wins[0][5][1] = true
                for (var k = 0; k < 5; k++) {
                    wins[i][j + k][count] = true
                }
                count++
            }
        }

        // 竖线赢法
        for (var i = 0; i < 15; i++) {
            for (var j = 0; j < 11; j++) {
                for (var k = 0; k < 5; k++) {
                    wins[j + k][i][count] = true
                }
                count++
            }
        }

        // 斜线赢法
        for (var i = 0; i < 11; i++) {
            for (var j = 0; j < 11; j++) {
                for (var k = 0; k < 5; k++) {
                    wins[i + k][j + k][count] = true
                }
                count++
            }
        }

        // 散斜线赢法
        for (var i = 0; i < 11; i++) {
            for (var j = 14; j > 3; j--) {
                for (var k = 0; k < 5; k++) {
                    wins[i + k][j - k][count] = true
                }
                count++
            }
        }

        console.log(count)

        for (var i = 0; i < count; i++) {
            myWin[i] = 0
            computerWin[i] = 0
        }

        context.strokeStyle = '#000'

        var logo = new Image()
        logo.src = 'https://s1.ax1x.com/2020/10/25/BeoauD.jpg'
        logo.onload = function () {
            context.drawImage(logo, 0, 0, 450, 450)
            drawChessBoard()
        }
        //画棋盘的功能函数利用循环和cavans画出棋盘
        var drawChessBoard = function () {
            for (var i = 0; i < 15; i++) {
                context.moveTo(15 + i * 30, 15)
                context.lineTo(15 + i * 30, 435)
                context.stroke()

                context.moveTo(15, 15 + i * 30)
                context.lineTo(435, 15 + i * 30)
                context.stroke()
            }
        }
        //onestep函数用于绘制游戏中落子的过程。其中，i、j表示落子的坐标，me表示落子的颜色，context是一个绘图上下文对象。函数内部先绘制一个半径为13的圆形，再通过createRadialGradient方法创建一个径向渐变对象gradient，并设置其颜色值。如果参数me为真，则把颜色值设为黑色，否则为白色。最后返回gradient径向渐变对象。
        var oneStep = function (i, j, me) {
            context.beginPath()
            context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI)
            context.closePath()
            var gradient = context.createRadialGradient(
                15 + i * 30 + 2, 15 + j * 30 - 2, 13,
                15 + i * 30 + 2, 15 + j * 30 - 2, 0,
            )
            if (me) {
                gradient.addColorStop(0, '#0A0A0A')
                gradient.addColorStop(1, '#636766')
            } else {
                gradient.addColorStop(0, '#D1D1D1')
                gradient.addColorStop(1, '#F9F9F9')
            }

            context.fillStyle = gradient
            context.fill()
        }
        //玩家棋子单机事件，将鼠标点击的位置加上棋子并且判断该次单击事件是否触发了上述
        // 集中赢法中的一条，如果有则弹出玩家胜利弹框
        chess.onclick = function (e) {
            if (over) {
                return
            }
            if (!me) {
                return
            }
            var x = e.offsetX
            var y = e.offsetY
            var i = Math.floor(x / 30)
            var j = Math.floor(y / 30)
            if (chessBoard[i][j] === 0) {
                oneStep(i, j, me)
                chessBoard[i][j] = 1

                for (var k = 0; k < count; k++) {
                    if (wins[i][j][k]) {
                        myWin[k]++
                        computerWin[k] = 6
                        if (myWin[k] === 5) {
                            window.alert('你赢了')
                            over = true
                        }
                    }
                }
                if (!over) {
                    me = !me
                    computerAI()
                }
            }
        }
        //电脑棋子单机事件，将鼠标点击的位置加上棋子并且判断该次单击事件是否触发了上述
        // 集中赢法中的一条，如果有则弹出电脑胜利弹框，这样实现了事件的人机交互功能。

        var computerAI = function () {
            var myScore = []
            var computerScore = []
            var max = 0
            var u = 0, v = 0
            for (var i = 0; i < 15; i++) {
                myScore[i] = []
                computerScore[i] = []
                for (var j = 0; j < 15; j++) {
                    myScore[i][j] = 0
                    computerScore[i][j] = 0
                }
            }
            for (var i = 0; i < 15; i++) {
                for (var j = 0; j < 15; j++) {
                    if (chessBoard[i][j] === 0) {
                        for (var k = 0; k < count; k++) {
                            if (wins[i][j][k]) {
                                if (myWin[k] === 1) {
                                    myScore[i][j] += 200
                                } else if (myWin[k] === 2) {
                                    myScore[i][j] += 400
                                } else if (myWin[k] === 3) {
                                    myScore[i][j] += 2000
                                } else if (myWin[k] === 4) {
                                    myScore[i][j] += 10000
                                }
                            }
                            if (wins[i][j][k]) {
                                if (computerWin[k] === 1) {
                                    computerScore[i][j] += 220
                                } else if (computerWin[k] === 2) {
                                    computerScore[i][j] += 420
                                } else if (computerWin[k] === 3) {
                                    computerScore[i][j] += 2100
                                } else if (computerWin[k] === 4) {
                                    computerScore[i][j] += 20000
                                }
                            }
                        }
                        if (myScore[i][j] > max) {
                            max = myScore[i][j]
                            u = i
                            v = j
                        } else if (myScore[i][j] === max) {
                            if (computerScore[i][j] > computerScore[u][v]) {
                                u = i
                                v = j
                            }
                        }

                        if (computerScore[i][j] > max) {
                            max = computerScore[i][j]
                            u = i
                            v = j
                        } else if (computerScore[i][j] === max) {
                            if (myScore[i][j] > myScore[u][v]) {
                                u = i
                                v = j
                            }
                        }
                    }
                }
            }
            oneStep(u, v, false)
            chessBoard[u][v] = 2
            for (var k = 0; k < count; k++) {
                if (wins[u][v][k]) {
                    computerWin[k]++
                    myWin[k] = 6
                    if (computerWin[k] === 5) {
                        window.alert('计算机赢了')
                        over = true
                    }
                }
            }
            if (!over) {
                me = !me
            }
        };
    </script>


</body>

</html>